home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume14 / rn-comments / part01 next >
Encoding:
Text File  |  1990-09-15  |  23.1 KB  |  728 lines

  1. Newsgroups: comp.sources.misc
  2. X-UNIX-From: em@dce.ie
  3. organization: Datacode Communications Ltd, Dublin, Ireland
  4. subject: v14i094: rn patch to identify posters of articles
  5. from: em@dce.ie (Eamonn McManus)
  6. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  7.  
  8. Posting-number: Volume 14, Issue 94
  9. Submitted-by: em@dce.ie (Eamonn McManus)
  10. Archive-name: rn-comments/part01
  11.  
  12. This patch to rn is intended to solve the problem where you are looking
  13. at a news article and think, "Isn't that the person who said...?"  It allows
  14. you to have a file containing a set of entries, each of which consists of a
  15. person's address and an associated comment.  The comment is printed out
  16. under the From line of any article by that person.  So if someone posts
  17. something really stupid (or really clever) you can arrange for all their
  18. subsequent articles to be branded (or emblazoned) with your own personal
  19. prejudice against (or for) that person.
  20.  
  21. #! /bin/sh
  22. # This is a shell archive.  Remove anything before this line, then unpack
  23. # it by saving it into a file and typing "sh file".  To overwrite existing
  24. # files, type "sh file -c".  You can also feed this as standard input via
  25. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  26. # will see the following message at the end:
  27. #        "End of shell archive."
  28. # Contents:  RNPREJUDICE RNPREJ.PATCH checkfrom.c stb.c stb.h
  29. # Wrapped by em@dce.ie on Tue Sep 11 23:38:38 1990
  30. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  31. if test -f RNPREJUDICE -a "${1}" != "-c" ; then 
  32.   echo shar: Will not over-write existing file \"RNPREJUDICE\"
  33. else
  34. echo shar: Extracting \"RNPREJUDICE\" \(3995 characters\)
  35. sed "s/^X//" >RNPREJUDICE <<'END_OF_RNPREJUDICE'
  36. XABOUT RNPREJUDICE
  37. X
  38. XThe rnprejudice patch is intended to solve the problem where you are looking
  39. Xat a news article and think, "Isn't that the person who said...?"  It allows
  40. Xyou to have a file containing a set of entries, each of which consists of a
  41. Xperson's address and an associated comment.  The comment is printed out
  42. Xunder the From line of any article by that person.  So if someone posts
  43. Xsomething really stupid (or really clever) you can arrange for all their
  44. Xsubsequent articles to be branded (or emblazoned) with your own personal
  45. Xprejudice against (or for) that person.
  46. X
  47. XThe modified rn looks in the RNPREJUDICE environment variable for the name
  48. Xof the prejudice file.  You can define this variable in your login script,
  49. Xor via the -E option to rn.
  50. X
  51. XLines in the prejudice file beginning with # are comments.  Unindented lines
  52. Xcontain mail addresses which are checked against the From line of each
  53. Xarticle.  If a match is found, the indented lines following the match will
  54. Xbe printed.  The From line must match exactly, i.e., the case of letters
  55. Xmust be the same.  The parenthesised personal name is ignored in the match.
  56. X
  57. X# Here is an example rnprejudice file.
  58. Xem@dce.ie
  59. X    Author of rnprejudice patch
  60. Xemcmanus@cs.tcd.ie
  61. X    Author of rnprejudice patch
  62. X# If someone has multiple addresses, they must have multiple entries.
  63. Xquestionable@severed-head.com
  64. X    Believes that the Earth is flat, that skyscapers are the remnants of
  65. X    a lost civilisation, and that Reagan wasn't so bad after all.
  66. XBIFF@BIT.NET
  67. X    Classic BIFF
  68. X
  69. XIn your .rnmac file you might define a macro like this:
  70. X# Edit the rnprejudice file
  71. X*    !echo '%t' >>$RNPREJUDICE; vi + $RNPREJUDICE\n
  72. XThis appends the e-mail address from the current article to the prejudice
  73. Xfile and starts you up in the editor, where you can add the comment.  When
  74. Xyou return from the edit, rn will notice that the file has been edited and
  75. Xread in the new copy.
  76. X
  77. X
  78. XAPPLYING THE PATCH
  79. X
  80. XIn the rn source directory, feed the file RNPREJ.PATCH to the patch program.
  81. XThis makes a small change to art.c so that it calls a function to look up
  82. Xthe From line of an article after displaying it, and modifies the Makefile
  83. Xto know about the new files checkfrom.c, stb.c, and stb.h.  Because the
  84. Xchanges are so small, they should work with most versions of rn.  The patch
  85. Xwas derived from version 4.3.2.2, patchlevel 44.
  86. X
  87. X"make rn" should recompile rn without problems.  If the new files fail to
  88. Xcompile, mail me <em@dce.ie> with a description of the problem.
  89. X
  90. X
  91. XIMPLEMENTATION NOTES
  92. X
  93. XSince the prejudice entries are kept entirely in memory, the patched rn
  94. Xprobably won't run on machines with small address spaces.
  95. X
  96. XThe in-memory data are handled by the code in stb.c.  This uses a binary
  97. Xtree for each possible initial letter.  If you keep your rnprejudice file
  98. Xin alphabetical order, performance will be bad.  A hash table might be
  99. Xbetter, but I wanted to avoid a big overhead when the prejudice file is
  100. Xsmall.  (In my experience it grows pretty quickly, though.)  It would be
  101. Xeasy to replace this file with a different implementation.
  102. X
  103. XThere are some things that could be improved:
  104. X* Lookups should not be case-sensitive, at least for the domain portion of
  105. X  the address.  The addresses in people's postings tend to show up with
  106. X  consistent case however.
  107. X* It would be convenient if you could have different aliases for the same
  108. X  person, rather than having to enter the same prejudice multiple times as
  109. X  at present.  Each block of unindented lines could be taken as a set of
  110. X  addresses for the same person.
  111. X* It might be better to look up the name in the parenthesised comment instead
  112. X  of or as well as the mail address.
  113. X* If you change the RNPREJUDICE environment variable within rn (using &-E)
  114. X  the code does not notice.  This could be fixed, but I don't see any need
  115. X  at present.
  116. X
  117. X
  118. XSTATUS
  119. X
  120. XThis patch is by Eamonn McManus, Datacode Communications Ltd <em@dce.ie>.
  121. XIt is not copyrighted and may be used freely.
  122. X
  123. X$Id: RNPREJUDICE,v 1.1 90/09/11 23:01:34 em Exp $
  124. END_OF_RNPREJUDICE
  125. if test 3995 -ne `wc -c <RNPREJUDICE`; then
  126.     echo shar: \"RNPREJUDICE\" unpacked with wrong size!
  127. fi
  128. # end of overwriting check
  129. fi
  130. if test -f RNPREJ.PATCH -a "${1}" != "-c" ; then 
  131.   echo shar: Will not over-write existing file \"RNPREJ.PATCH\"
  132. else
  133. echo shar: Extracting \"RNPREJ.PATCH\" \(4738 characters\)
  134. sed "s/^X//" >RNPREJ.PATCH <<'END_OF_RNPREJ.PATCH'
  135. X*** art.c.old    Thu Jan 25 20:51:50 1990
  136. X--- art.c    Tue Sep 11 21:09:11 1990
  137. X***************
  138. X*** 193,198 ****
  139. X--- 193,201 ----
  140. X          restart = Nullch;    /* and reset the flag */
  141. X          }
  142. X          else {            /* not a restart */
  143. X+         /* em@dce.ie: look up From in prejudice database. */
  144. X+         if (in_header == FROM_LINE)
  145. X+             linenum += checkfrom(art_buf);
  146. X          if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
  147. X                      /* if all done */
  148. X              mode = oldmode;
  149. X*** Makefile.old    Sat Jan 20 18:15:38 1990
  150. X--- Makefile    Mon Aug 13 22:32:49 1990
  151. X***************
  152. X*** 55,61 ****
  153. X  h1 = addng.h art.h artio.h artsrch.h backpage.h bits.h cheat.h common.h
  154. X  h2 = final.h head.h help.h init.h intrp.h kfile.h last.h ndir.h ng.h
  155. X  h3 = ngdata.h ngsrch.h ngstuff.h only.h rcln.h rcstuff.h
  156. X! h4 = respond.h rn.h search.h sw.h term.h util.h
  157. X  
  158. X  h = $(h1) $(h2) $(h3) $(h4) $(h5)
  159. X  
  160. X--- 55,61 ----
  161. X  h1 = addng.h art.h artio.h artsrch.h backpage.h bits.h cheat.h common.h
  162. X  h2 = final.h head.h help.h init.h intrp.h kfile.h last.h ndir.h ng.h
  163. X  h3 = ngdata.h ngsrch.h ngstuff.h only.h rcln.h rcstuff.h
  164. X! h4 = respond.h rn.h search.h sw.h term.h util.h stb.h
  165. X  
  166. X  h = $(h1) $(h2) $(h3) $(h4) $(h5)
  167. X  
  168. X***************
  169. X*** 62,68 ****
  170. X  c1 = addng.c art.c artio.c artsrch.c backpage.c bits.c cheat.c
  171. X  c2 = final.c head.c help.c init.c intrp.c kfile.c last.c $(NDIRC) ng.c
  172. X  c3 = ngdata.c ngsrch.c ngstuff.c only.c rcln.c rcstuff.c
  173. X! c4 = respond.c rn.c search.c sw.c term.c util.c
  174. X  
  175. X  c = $(c1) $(c2) $(c3) $(c4) $(c5)
  176. X  
  177. X--- 62,68 ----
  178. X  c1 = addng.c art.c artio.c artsrch.c backpage.c bits.c cheat.c
  179. X  c2 = final.c head.c help.c init.c intrp.c kfile.c last.c $(NDIRC) ng.c
  180. X  c3 = ngdata.c ngsrch.c ngstuff.c only.c rcln.c rcstuff.c
  181. X! c4 = respond.c rn.c search.c sw.c term.c util.c checkfrom.c stb.c
  182. X  
  183. X  c = $(c1) $(c2) $(c3) $(c4) $(c5)
  184. X  
  185. X***************
  186. X*** 69,75 ****
  187. X  obj1 = addng.o art.o artio.o artsrch.o backpage.o bits.o cheat.o
  188. X  obj2 = final.o head.o help.o init.o intrp.o kfile.o last.o $(NDIRO) ng.o
  189. X  obj3 = ngdata.o ngsrch.o ngstuff.o only.o rcln.o rcstuff.o
  190. X! obj4 = respond.o rn.o search.o sw.o term.o util.o
  191. X  
  192. X  obj = $(obj1) $(obj2) $(obj3) $(obj4) $(obj5)
  193. X  
  194. X--- 69,75 ----
  195. X  obj1 = addng.o art.o artio.o artsrch.o backpage.o bits.o cheat.o
  196. X  obj2 = final.o head.o help.o init.o intrp.o kfile.o last.o $(NDIRO) ng.o
  197. X  obj3 = ngdata.o ngsrch.o ngstuff.o only.o rcln.o rcstuff.o
  198. X! obj4 = respond.o rn.o search.o sw.o term.o util.o checkfrom.o stb.o
  199. X  
  200. X  obj = $(obj1) $(obj2) $(obj3) $(obj4) $(obj5)
  201. X  
  202. X*** Makefile.SH.old    Sat Jan 20 17:57:51 1990
  203. X--- Makefile.SH    Mon Aug 13 16:26:13 1990
  204. X***************
  205. X*** 64,70 ****
  206. X  h1 = addng.h art.h artio.h artsrch.h backpage.h bits.h cheat.h common.h
  207. X  h2 = final.h head.h help.h init.h intrp.h kfile.h last.h ndir.h ng.h
  208. X  h3 = ngdata.h ngsrch.h ngstuff.h only.h rcln.h rcstuff.h
  209. X! h4 = respond.h rn.h search.h sw.h term.h util.h
  210. X  #NNTPh5 = server.h
  211. X  
  212. X  h = $(h1) $(h2) $(h3) $(h4) $(h5)
  213. X--- 64,70 ----
  214. X  h1 = addng.h art.h artio.h artsrch.h backpage.h bits.h cheat.h common.h
  215. X  h2 = final.h head.h help.h init.h intrp.h kfile.h last.h ndir.h ng.h
  216. X  h3 = ngdata.h ngsrch.h ngstuff.h only.h rcln.h rcstuff.h
  217. X! h4 = respond.h rn.h search.h sw.h term.h util.h stb.h
  218. X  #NNTPh5 = server.h
  219. X  
  220. X  h = $(h1) $(h2) $(h3) $(h4) $(h5)
  221. X***************
  222. X*** 72,78 ****
  223. X  c1 = addng.c art.c artio.c artsrch.c backpage.c bits.c cheat.c
  224. X  c2 = final.c head.c help.c init.c intrp.c kfile.c last.c $(NDIRC) ng.c
  225. X  c3 = ngdata.c ngsrch.c ngstuff.c only.c rcln.c rcstuff.c
  226. X! c4 = respond.c rn.c search.c sw.c term.c util.c
  227. X  #NNTPc5 = $(NNTPDIR)/common/clientlib.c
  228. X  
  229. X  c = $(c1) $(c2) $(c3) $(c4) $(c5)
  230. X--- 72,78 ----
  231. X  c1 = addng.c art.c artio.c artsrch.c backpage.c bits.c cheat.c
  232. X  c2 = final.c head.c help.c init.c intrp.c kfile.c last.c $(NDIRC) ng.c
  233. X  c3 = ngdata.c ngsrch.c ngstuff.c only.c rcln.c rcstuff.c
  234. X! c4 = respond.c rn.c search.c sw.c term.c util.c checkfrom.c stb.c
  235. X  #NNTPc5 = $(NNTPDIR)/common/clientlib.c
  236. X  
  237. X  c = $(c1) $(c2) $(c3) $(c4) $(c5)
  238. X***************
  239. X*** 80,86 ****
  240. X  obj1 = addng.o art.o artio.o artsrch.o backpage.o bits.o cheat.o
  241. X  obj2 = final.o head.o help.o init.o intrp.o kfile.o last.o $(NDIRO) ng.o
  242. X  obj3 = ngdata.o ngsrch.o ngstuff.o only.o rcln.o rcstuff.o
  243. X! obj4 = respond.o rn.o search.o sw.o term.o util.o
  244. X  #NNTPobj5 =  $(NNTPDIR)/common/clientlib.o
  245. X  
  246. X  obj = $(obj1) $(obj2) $(obj3) $(obj4) $(obj5)
  247. X--- 80,86 ----
  248. X  obj1 = addng.o art.o artio.o artsrch.o backpage.o bits.o cheat.o
  249. X  obj2 = final.o head.o help.o init.o intrp.o kfile.o last.o $(NDIRO) ng.o
  250. X  obj3 = ngdata.o ngsrch.o ngstuff.o only.o rcln.o rcstuff.o
  251. X! obj4 = respond.o rn.o search.o sw.o term.o util.o checkfrom.o stb.o
  252. X  #NNTPobj5 =  $(NNTPDIR)/common/clientlib.o
  253. X  
  254. X  obj = $(obj1) $(obj2) $(obj3) $(obj4) $(obj5)
  255. END_OF_RNPREJ.PATCH
  256. if test 4738 -ne `wc -c <RNPREJ.PATCH`; then
  257.     echo shar: \"RNPREJ.PATCH\" unpacked with wrong size!
  258. fi
  259. # end of overwriting check
  260. fi
  261. if test -f checkfrom.c -a "${1}" != "-c" ; then 
  262.   echo shar: Will not over-write existing file \"checkfrom.c\"
  263. else
  264. echo shar: Extracting \"checkfrom.c\" \(4004 characters\)
  265. sed "s/^X//" >checkfrom.c <<'END_OF_checkfrom.c'
  266. X/* checkfrom.c - print information about news article originator. */
  267. X
  268. X/* By Eamonn McManus, <em@dce.ie>.  This file is not copyrighted.
  269. X * $Id: checkfrom.c,v 1.2 90/09/11 23:37:39 em Exp $
  270. X *
  271. X * This file contains the checkfrom() function, invoked from (modified) rn
  272. X * after a From: header line to see if the person named is mentioned in the
  273. X * RNPREJUDICE file.  If so, the text for that person is printed, and the
  274. X * number of lines that were printed is returned.  If not, 0 is returned.
  275. X *
  276. X * Each key in the file is on a line of its own,
  277. X * followed by zero or more data lines starting with whitespace.  Lines
  278. X * beginning with # are comments, as are leading indented lines.
  279. X */
  280. X
  281. X#include <stdio.h>
  282. X#include <ctype.h>
  283. X#include <sys/types.h>
  284. X#include <sys/stat.h>
  285. X#include "config.h"
  286. X#ifdef __STDC__
  287. X#include <stdlib.h>
  288. X#include <string.h>
  289. X#undef index
  290. X#define index strchr
  291. X#else
  292. Xextern char *malloc();
  293. Xextern void free();
  294. Xextern char *getenv();
  295. Xextern char *index();
  296. X#endif
  297. X
  298. Xtypedef char *datum;
  299. X#include "stb.h"
  300. X
  301. X
  302. Xextern char *savestr ARGS((char *str));
  303. X
  304. Xstatic stb *db;
  305. X
  306. X
  307. X/* Read the file into memory.  Return the number of keys read, or -1 on error.
  308. X */
  309. Xstatic int read_file(f)
  310. Xregister FILE *f;
  311. X{
  312. X    register int c, i;
  313. X    int nkeys;
  314. X    char key[1024];        /* Hardcoded limits; tough. */
  315. X    char data[4096], *datacopy;
  316. X    if (db == NULL && (db = stb_new_table()) == NULL)
  317. X        return -1;
  318. X    nkeys = 0;
  319. X    /* Each iteration reads a key and following data. */
  320. X    while ((c = getc(f)) != EOF) {
  321. X        /* Get the key. */
  322. X        for (i = 0; i < sizeof key - 1 && c != '\n'; c = getc(f)) {
  323. X            if (c == EOF)
  324. X                return nkeys;
  325. X            key[i++] = c;
  326. X        }
  327. X        if (i == 0 || key[0] == '#' || isspace(key[0]))
  328. X            continue;
  329. X        key[i] = '\0';
  330. X        /* Get the data. */
  331. X        i = 0;
  332. X        /* Read the indented lines. */
  333. X        while (isspace(c = getc(f))) {
  334. X            /* Read a line. */
  335. X            while (1) {
  336. X                if (c == EOF)
  337. X                    return nkeys;
  338. X                if (i < sizeof data - 1)
  339. X                    data[i++] = c;
  340. X                if (c == '\n')
  341. X                    break;
  342. X                c = getc(f);
  343. X            }
  344. X        }
  345. X        (void) ungetc(c, f);
  346. X        data[i] = '\0';
  347. X        datacopy = savestr(data);
  348. X        if (stb_insert(db, key, &datacopy) == NULL) {
  349. X            free(datacopy);
  350. X        } else nkeys++;
  351. X    }
  352. X    return nkeys;
  353. X}
  354. X
  355. X
  356. X/* Action function for stb_free_tree. */
  357. Xstatic int sfree(p)
  358. Xchar *p;
  359. X{
  360. X    free(p);
  361. X    return 0;
  362. X}
  363. X
  364. X
  365. X/* See if the electronic address in the fromline appears in the prejudice
  366. X * database.  If so, print the indented lines that follow.  Return the
  367. X * number of lines printed.  The string pointed to by fromline is modified.
  368. X */
  369. Xint checkfrom(fromline)
  370. Xregister char *fromline;
  371. X{
  372. X    register char *p, *dbname;
  373. X    register stb_node *s;
  374. X    int lines, t;
  375. X    static char beenhere;
  376. X    static FILE *f;
  377. X    static time_t mtime;
  378. X    struct stat st;
  379. X    /* Slurp in the database if we haven't already, or if it has been
  380. X     * modified since we read it.
  381. X     */
  382. X    if (beenhere) {
  383. X        if (f == NULL)
  384. X            return 0;
  385. X        if ((t = fstat(fileno(f), &st)) < 0 || st.st_mtime > mtime) {
  386. X            (void) stb_free_table(db, sfree); db = NULL;
  387. X            if (t < 0) {
  388. X                fclose(f); f = NULL;
  389. X                return 0;
  390. X            } else {
  391. X                rewind(f);
  392. X                mtime = st.st_mtime;
  393. X                beenhere = 0;
  394. X            }
  395. X        }
  396. X    } else {
  397. X        if ((dbname = getenv("RNPREJUDICE")) == NULL)
  398. X            return 0;
  399. X        if ((f = fopen(dbname, "r")) == NULL ||
  400. X            fstat(fileno(f), &st) < 0) {
  401. X            printf("[Could not open RNPREJUDICE=\"%s\"]\n", dbname);
  402. X            f = NULL;
  403. X            return 1;
  404. X        }
  405. X        mtime = st.st_mtime;
  406. X    }
  407. X    if (!beenhere) {
  408. X        beenhere++;
  409. X        if (read_file(f) < 0) {
  410. X            printf("[Format error in $RNPREJUDICE]\n");
  411. X            fclose(f); f = NULL;
  412. X            return 1;
  413. X        }
  414. X    }
  415. X    /* Isolate the address part of the from line.  Skip the initial
  416. X     * "From:" as well as any trailing stuff (usually the personal
  417. X     * name comment).
  418. X     */
  419. X    for ( ; *fromline && !isspace(*fromline); fromline++) ;
  420. X    for ( ; isspace(*fromline); fromline++) ;
  421. X    for (p = fromline; *p && !isspace(*p); p++) ;
  422. X    if (p == fromline)
  423. X        return 0;
  424. X    *p = '\0';
  425. X    if ((s = stb_lookup(db, fromline)) == NULL)
  426. X        return 0;
  427. X    fputs(s->datum, stdout);
  428. X    for (lines = 0, p = s->datum; (p = index(p, '\n')) != NULL;
  429. X         lines++, p++) ;
  430. X    return lines;
  431. X}
  432. END_OF_checkfrom.c
  433. if test 4004 -ne `wc -c <checkfrom.c`; then
  434.     echo shar: \"checkfrom.c\" unpacked with wrong size!
  435. fi
  436. # end of overwriting check
  437. fi
  438. if test -f stb.c -a "${1}" != "-c" ; then 
  439.   echo shar: Will not over-write existing file \"stb.c\"
  440. else
  441. echo shar: Extracting \"stb.c\" \(6095 characters\)
  442. sed "s/^X//" >stb.c <<'END_OF_stb.c'
  443. X/* stb.c - symbol table functions */
  444. X
  445. X/* By Eamonn McManus <em@dce.ie>.  This file is not copyrighted.
  446. X * $Id: stb.c,v 1.2 90/09/11 23:37:49 em Exp $
  447. X *
  448. X * Functions using a simple binary forest to implement symbol table
  449. X * operations.  Should be recompiled with DATUM defined on the command
  450. X * line as a declaration for variable datum of suitable type.  Default
  451. X * is equivalent to -DDATUM="char *datum".
  452. X */
  453. X
  454. X#ifndef DATUM
  455. X#define DATUM char *datum
  456. X#endif
  457. X
  458. Xtypedef DATUM;
  459. X
  460. X#include "stb.h"
  461. X#ifdef __STDC__
  462. X#include <string.h>    /* For strcpy(). */
  463. X#include <stdlib.h>
  464. X#else
  465. Xextern char *malloc();
  466. Xextern char *strcpy();
  467. Xextern void free();
  468. X#endif
  469. X
  470. X#ifndef NULL
  471. X# define NULL 0
  472. X#endif
  473. X
  474. X
  475. X/* Return a new symbol table.  NULL if can't make one. */
  476. Xstb *stb_new_table()
  477. X{
  478. X    /* Note that calloc() to get an array of NULLs is not portable. */
  479. X    register int i;
  480. X    register stb *s = (stb *) malloc(sizeof(stb));
  481. X    for (i = 0; i < MAXCHAR; i++)
  482. X        (*s)[i] = NULL;
  483. X    return s;
  484. X}
  485. X
  486. X
  487. X/* Free tree rooted at root, using function datumfree. */
  488. Xstatic int free_tree(root, datumfree)
  489. Xregister stb_node *root;
  490. Xregister int (*datumfree)();
  491. X{
  492. X    register stb_node *n;
  493. X    for ( ; root != NULL; root = n) {
  494. X        if (free_tree(root->link[0], datumfree) < 0)
  495. X            return -1;
  496. X        n = root->link[1];
  497. X        if ((*datumfree)(root->datum) < 0)
  498. X            return -1;
  499. X        free((char *) root->name);
  500. X        free((char *) root);
  501. X    }
  502. X    return 0;
  503. X}
  504. X
  505. X
  506. X/* Free a symbol table.  Return 0 if OK, -1 if error.  Datumfree is a
  507. X * routine to free the datum in each node, returning the same error status.
  508. X */
  509. Xint stb_free_table(table, datumfree)
  510. Xregister stb *table;
  511. Xregister int (*datumfree)();
  512. X{
  513. X    register int i;
  514. X    for (i = 0; i < MAXCHAR; i++)
  515. X        if (free_tree((*table)[i], datumfree) < 0)
  516. X            return -1;
  517. X    free((char *) table);
  518. X    return 0;
  519. X}
  520. X
  521. X
  522. X/* Look up a symbol.  Return pointer to its node or NULL if not found. */
  523. Xstb_node *stb_lookup(table, name)
  524. Xstb *table;
  525. Xregister char *name;
  526. X{
  527. X    register stb_node *n;
  528. X    register int order;
  529. X    if (name[0] == '\0')
  530. X        return (*table)['\0'];    /* Only one null symbol. */
  531. X    if ((unsigned char) name[0] >= MAXCHAR)
  532. X        return NULL;        /* Invalid. */
  533. X    for (n = (*table)[(unsigned char) *name++]; n; n = n->link[order > 0])
  534. X        if ((order = strcmp(name, n->name + 1)) == 0)
  535. X            return n;
  536. X    return NULL;
  537. X}
  538. X
  539. X
  540. X/* Insert a symbol.  Returns the inserted node, or NULL if there was an
  541. X * error or the symbol was already present.
  542. X */
  543. Xstb_node *stb_insert(table, name, newdatum)
  544. Xstb *table;
  545. Xregister char *name;
  546. Xdatum *newdatum;
  547. X{
  548. X    register stb_node *parent, *n, **link;
  549. X    register int order;
  550. X    register char *namecpy;
  551. X    if ((unsigned char) *name >= MAXCHAR)
  552. X        return NULL;        /* Invalid. */
  553. X    parent = NULL;
  554. X    link = *table + (unsigned char) name[0];
  555. X    n = *link;
  556. X    if (*name++) {            /* Only one null symbol, no search. */
  557. X        while (n != NULL) {
  558. X            if ((order = strcmp(name, n->name + 1)) == 0)
  559. X                break;
  560. X            link = &n->link[order > 0];
  561. X            parent = n; n = *link;
  562. X        }
  563. X    }
  564. X    if (n != NULL)
  565. X        return NULL;        /* Already present. */
  566. X    if ((namecpy = malloc((unsigned) strlen(--name) + 1)) == NULL)
  567. X        return NULL;        /* Out of memory. */
  568. X    (void) strcpy(namecpy, name);
  569. X    if ((n = (stb_node *) malloc(sizeof(stb_node))) == NULL)
  570. X        return NULL;
  571. X    n->link[0] = n->link[1] = NULL;
  572. X    n->parent = parent; n->name = namecpy; n->datum = *newdatum;
  573. X    *link = n;
  574. X    return n;
  575. X}
  576. X
  577. X
  578. X/* Subsequent functions are not used in the rnprejudice code. */
  579. X#ifdef UNPREJUDICED
  580. X
  581. X/* Return lowest valued descendant of node. */
  582. Xstatic stb_node *first(node)
  583. Xregister stb_node *node;
  584. X{
  585. X    while (node->link[0] != NULL)
  586. X        node = node->link[0];
  587. X    return node;
  588. X}
  589. X
  590. X
  591. X/* Return first symbol in table, NULL if table is empty. */
  592. Xstb_node *stb_first(table)
  593. Xregister stb *table;
  594. X{
  595. X    register int i;
  596. X    for (i = 0; i < MAXCHAR; i++)
  597. X        if ((*table)[i] != NULL)
  598. X            return first((*table)[i]);
  599. X    return NULL;
  600. X}
  601. X
  602. X
  603. X/* Return the next symbol after the given node, NULL if none. */
  604. Xstb_node *stb_next(table, node)
  605. Xstb *table;
  606. Xregister stb_node *node;
  607. X{
  608. X    register int i;
  609. X    /* If there is a right pointer, return its smallest descendant.
  610. X     * If this is the left descendant of a node, return that node.
  611. X     * Otherwise, we want that node's next.
  612. X     */
  613. X    if (node->link[1] != NULL)
  614. X        return first(node->link[1]);
  615. X    for ( ; node->parent != NULL; node = node->parent)
  616. X        if (node->parent->link[0] == node)
  617. X            return node->parent;
  618. X    /* At root for this initial char.  Find next tree. */
  619. X    for (i = node->name[0] + 1; i < MAXCHAR; i++)
  620. X        if ((*table)[i])
  621. X            return first((*table)[i]);
  622. X    return NULL;
  623. X}
  624. X
  625. X
  626. X/* Delete a node.  Return 0 if OK, else -1.  Datumfree is a function to
  627. X * free the datum part of the node, returning the same kind of status.
  628. X */
  629. Xint stb_delete(table, node, datumfree)
  630. Xstb *table;
  631. Xregister stb_node *node;
  632. Xint (*datumfree)();
  633. X{
  634. X    register stb_node **link, *succ;
  635. X    /* Find the link from the parent that we want to change. */
  636. X    if (node->parent == NULL)
  637. X        link = *table + node->name[0];    /* In the array of roots. */
  638. X    else    link = &node->parent->link[node->parent->link[1] == node];
  639. X    /* If either descendant is NULL, replace with the other.  Otherwise
  640. X     * find the successor and replace with that.
  641. X     */
  642. X    if (node->link[0] == NULL)
  643. X        *link = node->link[1];
  644. X    else if (node->link[1] == NULL)
  645. X        *link = node->link[0];
  646. X    else {
  647. X        succ = first(node->link[1]);
  648. X        /* Replace the deleted node with its successor, succ.  Succ
  649. X         * has no left child (since that would be the successor), so
  650. X         * it inherits the original node's left child.
  651. X         * If succ is the right child of the original node, that is
  652. X         * enough.  Otherwise, succ's parent
  653. X         * inherits succ's right child as its left child (which was
  654. X         * succ), and succ inherits the original node's right child.
  655. X         */
  656. X        succ->link[0] = node->link[0]; node->link[0]->parent = succ;
  657. X        if (succ->parent != node) {
  658. X            succ->parent->link[0] = succ->link[1];
  659. X            if (succ->link[1] != NULL)
  660. X                succ->link[1]->parent = succ->parent;
  661. X            succ->link[1] = node->link[1];
  662. X                node->link[1]->parent = succ;
  663. X        }
  664. X        *link = succ;
  665. X    }
  666. X    if (*link != NULL)
  667. X        (*link)->parent = node->parent;
  668. X    if ((*datumfree)(node->datum) < 0)
  669. X        return -1;
  670. X    free((char *)node->name); free((char *)node);
  671. X    return 0;
  672. X}
  673. X
  674. X#endif    /* UNPREJUDICED */
  675. END_OF_stb.c
  676. if test 6095 -ne `wc -c <stb.c`; then
  677.     echo shar: \"stb.c\" unpacked with wrong size!
  678. fi
  679. # end of overwriting check
  680. fi
  681. if test -f stb.h -a "${1}" != "-c" ; then 
  682.   echo shar: Will not over-write existing file \"stb.h\"
  683. else
  684. echo shar: Extracting \"stb.h\" \(871 characters\)
  685. sed "s/^X//" >stb.h <<'END_OF_stb.h'
  686. X/* stb.h - declarations for symbol-table package stb.c. */
  687. X
  688. X/* By Eamonn McManus <em@dce.ie>.  This file is not copyrighted.
  689. X * $Id: stb.h,v 1.2 90/09/11 23:38:07 em Exp $
  690. X */
  691. X
  692. X#ifndef MAXCHAR
  693. X# define MAXCHAR 256
  694. X#endif
  695. X
  696. Xtypedef struct stb_node {
  697. X    struct stb_node *link[2], *parent;
  698. X    char *name;
  699. X    datum datum;        /* datum must be typedef'd first. */
  700. X} stb_node;
  701. X
  702. Xtypedef stb_node *stb[MAXCHAR];
  703. X
  704. X#ifndef ARGS
  705. X# ifndef __STDC__
  706. X#  define ARGS(x) ()
  707. X# else
  708. X#  define ARGS(x) x
  709. X# endif
  710. X#endif
  711. X
  712. Xstb *stb_new_table ARGS((void));
  713. Xint stb_free_table ARGS((stb *table, int (*datumfree)()));
  714. Xstb_node *stb_lookup ARGS((stb *table, char *name));
  715. Xstb_node *stb_insert ARGS((stb *table, char *name, datum *newdatum));
  716. Xstb_node *stb_first ARGS((stb *table));
  717. Xstb_node *stb_next ARGS((stb *table, stb_node *node));
  718. Xint stb_delete ARGS((stb *table, stb_node *node, int (*datumfree)()));
  719. END_OF_stb.h
  720. if test 871 -ne `wc -c <stb.h`; then
  721.     echo shar: \"stb.h\" unpacked with wrong size!
  722. fi
  723. # end of overwriting check
  724. fi
  725. echo shar: End of shell archive.
  726. exit 0
  727.  
  728.